package com.hps.demo.provider;

import com.hps.demo.annotation.RpcService;
import com.hps.demo.api.RpcRequest;
import com.hps.demo.registry.RegisterCenter;
import com.hps.demo.registry.RegisterCenterWithZk;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author hps
 * @Description:
 * @Date Created in 18:38 2019/7/11
 */
public class RpcProvider implements InitializingBean, ApplicationContextAware {

    private static ConcurrentHashMap<String, Object> serviceMap = new ConcurrentHashMap<>();

    private RegisterCenter registerCenter = new RegisterCenterWithZk();

    private AtomicInteger count = new AtomicInteger(0);

    @Override
    public void afterPropertiesSet() throws Exception {

        try {
            ServerSocket server = new ServerSocket(8890);

            while (true) {
                Socket socket = server.accept();
                InputStream inputStream = socket.getInputStream();

                ObjectInputStream ois = new ObjectInputStream(inputStream);

                RpcRequest request = (RpcRequest) ois.readObject();

                String className = request.getClassName();
                Object service = serviceMap.get(className);
                Class<?> clazz = Class.forName(className);
                Method method = clazz.getMethod(request.getMethodName(), request.getParameterTypes());
                Object result = method.invoke(service, request.getArgs());

                OutputStream os = socket.getOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(os);
                oos.writeObject(result);
                os.flush();

                os.close();
                inputStream.close();
                socket.close();

                int times = count.getAndIncrement();
                if (times >= 5) {
                    registerCenter.close();
                    server.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        Map<String, Object> beanMap = context.getBeansWithAnnotation(RpcService.class);
        System.out.println(beanMap);

        String serviceAddress = getAddress() + ":8888";
        for (Object value : beanMap.values()) {
            Class<?>[] interfaces = value.getClass().getInterfaces();
            for (Class<?> i : interfaces) {
                serviceMap.put(i.getName(), value);
                registerCenter.register(i.getName(), serviceAddress);
            }
        }
    }

    private static String getAddress(){
        InetAddress inetAddress=null;
        try {
            inetAddress=InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return inetAddress.getHostAddress();// 获得本机的ip地址
    }
}
